
package com.gitee.jmash.oidc.oauth2.impl;

import org.apache.commons.lang3.StringUtils;
import com.gitee.jmash.oidc.oauth2.enums.GrantType;
import com.gitee.jmash.oidc.oauth2.enums.GrantWay;
import com.gitee.jmash.oidc.oauth2.enums.ScopeType;
import com.gitee.jmash.oidc.oauth2.models.ErrorResponse;
import com.gitee.jmash.oidc.oauth2.models.TokenRefreshModel;
import com.gitee.jmash.oidc.oauth2.models.TokenResponse;
import com.gitee.jmash.oidc.oauth2.utils.IdTokenUtil;
import com.gitee.jmash.oidc.web.Constant;
import com.gitee.jmash.oidc.web.OidcMapper;
import com.gitee.jmash.rbac.RbacFactory;
import com.gitee.jmash.rbac.entity.TokenEntity;
import com.xyvcard.ops.OpsFactory;
import com.xyvcard.ops.entity.OpsClientEntity;
import jakarta.enterprise.context.Dependent;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import jakarta.ws.rs.core.Response;
import jmash.rbac.protobuf.RefreshTokenReq;

/**
 * OAuth 2.0 更新令牌.
 *
 * @author CGD
 *
 */
@Dependent
public class OauthRefreshTokenImpl {

  /** refresh_token --> access_token. */
  public Response token(@Valid TokenRefreshModel token, HttpServletRequest request) {

    // 1.验证GrantType
    if (!GrantType.refresh_token.equals(token.getGrantType())) {
      return ErrorResponse.createResponse("invalid_grant", "invalid_grant不匹配.");
    }
    // 2.验证clientId、clientSecret
    OpsClientEntity client = OpsFactory.getOpsClientRead(Constant.TENANT)
        .findBySecret(token.getClientId(), token.getClientSecret());
    if (client == null || !client.allowGrantWay(GrantWay.code.name())) {
      return ErrorResponse.createResponse("invalid_client", "client_id身份认证错误或授权方式不一致.");
    }
    // 3.验证Code
    TokenEntity tokenEntity = RbacFactory.getUserRead(Constant.TENANT)
        .findTokenByRefreshToken(token.getClientId(), token.getRefreshToken());
    if (null == tokenEntity) {
      return ErrorResponse.createResponse("invalid_request", "refresh_token错误.");
    }

    // 4.生成并记录AccessToken
    RefreshTokenReq req = RefreshTokenReq.newBuilder().setTenant(Constant.TENANT)
        .setClientId(token.getClientId()).setRefreshToken(token.getRefreshToken()).build();
    tokenEntity = RbacFactory.getUserWrite(Constant.TENANT).refreshToken(req,true);

    TokenResponse resp = new TokenResponse();
    OidcMapper.INSTANCE.update(resp, tokenEntity);
    
    // id_token
    if (StringUtils.contains(resp.getScope(), ScopeType.openid.name())) {
      String idToken = IdTokenUtil.createIdToken(tokenEntity);
      resp.setIdToken(idToken);
    }

    return Response.ok().entity(resp).build();
  }
}
